Current File : /var/www/e360ban/wp-content/plugins/types/vendor/toolset/types/includes/autoloader.php |
<?php
/**
* Autoloader for Types classes.
*
* Note that this is less effective than it could be but we need to keep it as long as we have legacy code using it...
* the codebase is too fragile to justify any optimizations here.
*
* See:
* @link https://git.onthegosystems.com/toolset/layouts/wikis/layouts-theme-integration#wpddl_theme_integration_autoloader
*
* @since 2.0
*/
final class Types_Autoloader {
private static $instance;
/**
* @var array Multidimensional associative array:
*
* array(
* class prefix => array(
* path => array( ... options ... ),
* ...
* ),
* ...
* )
*
*/
private $paths_by_prefixes = array();
/**
* For production version of Types we use a class map
* you can disable using the classmap by simply deleting /autoload_classmap.php
*
* Note: Not using the classmap will lower the performance significant
*
* @var bool|array
* @since 2.1
*/
private $classmap = false;
private function __construct() {
spl_autoload_register( array( $this, 'autoload' ) );
if( file_exists( TYPES_ABSPATH . '/autoload_classmap.php' ) ) {
$this->classmap = include( TYPES_ABSPATH . '/autoload_classmap.php' );
}
}
public static function get_instance() {
if( self::$instance === null ) {
self::$instance = new self;
}
return self::$instance;
}
/**
* Add base path to search for class files.
*
* @param string $prefix Class prefix
* @param string $path Path for given class prefix
* @param array [$options] Additional options. Currently supported are:
* - file_prefix: Value that will be prepended before each file name that will be checked.
* @return bool True if path was added
*
* @since 2.0
*/
public function add_path( $prefix, $path, $options = array() ) {
if( ! array_key_exists( $prefix, $this->paths_by_prefixes ) ) {
$this->paths_by_prefixes[ $prefix ] = array();
// We assume that most specific (longest) prefixes will have higher probability of a match.
// This is useful when one prefix is substring of another.
krsort( $this->paths_by_prefixes );
}
// Skip if already set
if( in_array( $path, array_keys( $this->paths_by_prefixes[ $prefix ] ) ) ) {
return true;
}
// Abort if the path is not readable
if( ! is_readable( $path ) ) {
return false;
}
if( !is_array( $options ) ) {
$options = array();
}
$this->paths_by_prefixes[ $prefix ][ $path ] = $options;
return true;
}
/**
* Add multiple base paths.
*
* @param $prefix
*
* @param array $paths
* @param array $options
*
* @since 2.0
*/
public function add_paths( $prefix, $paths, $options = array() ) {
// run this->addPath for each value
foreach( $paths as $path ) {
$this->add_path( $prefix, $path, $options );
}
}
public function autoload( $class ) {
// use class map if defined
if( $this->classmap ) {
if( isset( $this->classmap[$class] ) && file_exists( $this->classmap[$class] ) ) {
require_once( $this->classmap[$class] );
return true;
}
return false;
}
// no class map
foreach( $this->paths_by_prefixes as $prefix => $paths ) {
// Will be equal to $class if no replacement happens.
$class_without_prefix = preg_replace( '#^'.$prefix.'_#', '', $class );
if( $class != $class_without_prefix ) {
$result = $this->try_autoload_without_prefix( $class, $class_without_prefix, $paths );
// false means we should try with other prefixes
if( false !== $result ) {
return $result;
}
}
}
return false;
}
/**
* Try to load class after matching it's prefix.
*
* @param string $full_class_name Full name of the class.
* @param string $class_name_without_prefix Name of the class without the registered prefix.
* @param array $paths Path definitions for current prefix.
*
* @return bool|mixed include_once() result or false if the file was not found.
*
* @since 2.0
*/
private function try_autoload_without_prefix( $full_class_name, $class_name_without_prefix, $paths ) {
// explode class by _
$explode_class = explode( '_' , $class_name_without_prefix );
// get class filename
$class_filename = array_pop( $explode_class );
$class_filename = strtolower( $class_filename ) . '.php';
// get class path
$class_path = '';
foreach( $explode_class as $path ) {
$class_path .= strtolower( $path ) . '/';
}
// check for file in path
foreach( $paths as $path => $options ) {
$file_prefix = wpcf_getarr( $options, 'file_prefix', '' );
$next_filename = $class_path . $file_prefix . $class_filename;
while( true ) {
$candidate_filename = $next_filename;
$candidate_path = $path . '/' . $candidate_filename;
$result = $this->try_load_file( $candidate_path, $full_class_name );
if( false !== $result ) {
return $result;
}
// Replace the last slash by underscore.
// This allows to use underscores in class filename instead of subfolders
$next_filename = preg_replace( '/(\/(?!.*\/))/', '_', $candidate_filename );
// If there was no change, we have tried all possibilities for this filename.
if( $next_filename == $candidate_filename ) {
break;
}
}
}
return false;
}
/**
* Try loading a file and check if given class exists afterwards.
*
* @param string $full_path Absolute path to the file.
* @param string $full_class_name Full class name to be checked.
*
* @return bool|mixed include_once() result or false if the class couldn't be loaded. It may give false negatives.
*/
private function try_load_file( $full_path, $full_class_name ) {
if( is_file( $full_path ) ) {
/** @noinspection PhpIncludeInspection */
$result = include_once( $full_path ) ;
// Do not stop trying if we load the file but it doesn't contain the requested class.
if( class_exists( $full_class_name ) ) {
return $result;
}
}
return false;
}
}